/*
 * Copyright 2012 Sergey Netesanyi.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.google.gwt.user.rebind.rpc;

import com.google.gwt.core.ext.BadPropertyValueException;
import com.google.gwt.core.ext.ConfigurationProperty;
import com.google.gwt.core.ext.GeneratorContext;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.versatile.gwt.serialization.client.util.CollectionUtil;

import java.util.ArrayList;
import java.util.List;

/**
 * Container of black and white serialization lists.
 *
 * @author Sergey Netesanyi
 * @version 1.0
 */
public class BlackWhiteList {
    /** Property name. */
    private static final String SERIALIZER_TYPES_PROPERTY = "serialization.allowedList";

    private List<JClassType> blackList;

    private List<JClassType> whiteList;

    protected void addBlackList(JClassType type) {
        blackList = CollectionUtil.newArrayListIfNull(blackList);
        blackList.add(type);
    }

    protected void addWhiteList(JClassType type) {
        if (whiteList == null) {
            whiteList = new ArrayList<JClassType>();
        }
        whiteList.add(type);
    }

    public boolean isAllowed(JClassType type) {
        if (blackList != null) {
            for (JClassType blackType : blackList) {
                if (type.isAssignableTo(blackType)) {
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * Gets the "whiteList".
     *
     * @return Returns the "whiteList".
     */
    public List<JClassType> getWhiteList() {
        return whiteList;
    }

    public void build(TreeLogger logger, GeneratorContext context)
            throws UnableToCompleteException {
        ConfigurationProperty prop;

        try {
            prop = context.getPropertyOracle().getConfigurationProperty(SERIALIZER_TYPES_PROPERTY);
            buildFilter(logger, context, prop.getValues());
        } catch (BadPropertyValueException e) {
            // no property - no exception.
        }

    }

    private void buildFilter(TreeLogger logger, GeneratorContext context, List<String> values)
            throws UnableToCompleteException {
        final TypeOracle typeOracle = context.getTypeOracle();
        for (String type : values) {
            char token = type.charAt(0);
            JClassType jType = typeOracle.findType(type.replaceAll("[+-]", ""));
            if (jType == null) {
                logger.branch(TreeLogger.Type.ERROR,
                        "Can not recognized type specified in '" + SERIALIZER_TYPES_PROPERTY + "' list. Type is " +
                                type);
                throw new UnableToCompleteException();
            }
            if (token == '-') {
                addBlackList(jType);
            } else {
                addWhiteList(jType);
            }
        }
    }

}
